package cn.edu.cqvie.jdk8.stream2;

import java.text.DecimalFormat;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;

public class MySetCollector2<T> implements Collector<T, Set<T>, Map<T, T>> {

    @Override
    public Supplier<Set<T>> supplier() {
        System.out.println("supplier invoked!");
//        return HashSet::new;

        /* A a1 = supplier.get();
         *     accumulator.accept(a1, t1);
         *     accumulator.accept(a1, t2);
         *     R r1 = finisher.apply(a1);  // result without splitting
         *
         *     A a2 = supplier.get();
         *     accumulator.accept(a2, t1);
         *     A a3 = supplier.get();
         *     accumulator.accept(a3, t2);
         *     R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting
         */
        return  () -> {
            System.out.println("-----------");
            return new HashSet<>();
        };
    }

    /**
     * A function that folds a value into a mutable result container.
     *
     * @return a function which folds a value into a mutable result container
     */
    @Override
    public BiConsumer<Set<T>, T> accumulator() {
        System.out.println("accumulator invoked!");

        return (set1, item) -> {
//            synchronized (set1) {
                System.out.println(" set " + set1 + " accumulator " + Thread.currentThread().getName());
                set1.add(item);
//            }
        };
    }

    /**
     * 并行流，并且 Characteristics.CONCURRENT
     */
    @Override
    public BinaryOperator<Set<T>> combiner() {
        System.out.println("combiner invoked!");
        return (set1, set2) -> {
            System.out.println("set1 : " + set1);
            System.out.println("set2 : " + set2);
            set1.addAll(set2);
            return set1;
        };
    }

    /**
     * Perform the final transformation from the intermediate accumulation type
     * {@code A} to the final result type {@code R}.
     *
     * <p>If the characteristic {@code IDENTITY_TRANSFORM} is
     * set, this function may be presumed to be an identity transform with an
     * unchecked cast from {@code A} to {@code R}.
     *
     * @return a function which transforms the intermediate result to the final
     * result
     */
    @Override
    public Function<Set<T>, Map<T, T>> finisher() {
        System.out.println("finisher invoked!");

        return set -> {
            Map<T, T> map = new TreeMap<>();
            set.forEach(item -> map.put(item, item));
            return map;
        };
    }

    /**
     * Returns a {@code Set} of {@code Collector.Characteristics} indicating
     * the characteristics of this Collector.  This set should be immutable.
     *
     * @return an immutable set of collector characteristics
     */
    @Override
    public Set<Characteristics> characteristics() {
        System.out.println("characteristics invoked!");
        // , Characteristics.IDENTITY_FINISH
        // , Characteristics.CONCURRENT 只有一个中间容器，不会调用combiner方法
        return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED));
    }


    public static void main(String[] args) {

        System.out.println(Runtime.getRuntime().availableProcessors());

        for (int i = 0; i < 100; i++) {
            List<String> list = Arrays.asList("hello", "world", "welcome", "a", "b", "c", "d", "e", "f", "g", "h");
            Set<String> set = new HashSet<>(list);

            System.out.println("set:" + set);
            System.out.println("set.size:" + set.size());

//        Map<String, String> map = set.stream().collect(new MySetCollector2<>());
//        System.out.println(map);

            Map<String, String> map = set.parallelStream().collect(new MySetCollector2<>());
            System.out.println(map);

            new LinkedList<>(list);

            DecimalFormat form = new DecimalFormat("#.#");


            System.out.println(1.0D / Double.valueOf(form.format(0.0)));
        }
    }
}
